package pdm.h_2011_01;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;


import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;


/**
 * Clasa implementeaza o intrare din lista de orase.
 *
 * @author Vlase Paul
 *
 */
class City implements Comparable<City>
{
	/**
	 * Numele orasului.
	 */
	private String name_;
	
	/**
	 * Constructorul clasei City.
	 * 
	 * @param name - numele orasului
	 */
	public City(String name)
	{
		name_ = name;
	}
	
	/**
	 * Returneaza numele orasului.
	 * 
	 * @return numele orasului
	 */
	public String getName()
	{
		return name_;
	}
	
	/**
	 * Returneaza reprezentarea ca string.
	 */
	public String toString()
	{
		return name_;
	}
	
	/**
	 * Compara obiectul cu un alt obiect.
	 * 
	 * @param c - obiectul cu care se compara
	 * 
	 * @return numar intreg < 0, mai mic ca obiectul c
	 *                      > 0, mai mare ca obiectul c
	 *                      = 0, egal cu obiectul c 
	 */
	public int compareTo(City c) {
	  return name_.compareTo(c.getName());
	}
}


/**
 * Clasa implementeaza adaptorul pentru o lista de orase.
 * 
 * @author Vlase Paul
 *
 */
class CityListAdapter extends BaseAdapter
{
	private Activity context_;
	ArrayList<City> cities_;

	/**
	 * Constructorul clasei CityListAdapter.
	 * 
	 * @param context - contextul listei
	 */
	public CityListAdapter (Activity context)
	{
		context_ = context;
		cities_ = new ArrayList<City>();
	}

	/**
	 *  Metoda intoarce view-ul de pe pozitia position din lista.
	 *  
	 *  @position - pozitia
	 *  @convertiView - este un element din lista ce nu mai este vizibil si 
	 *  				  poate fi convertit
	 *  @list - lista
	 *  
	 *  @return vie-ul de pe pozitia position
	 */
	public View getView (int position, View convertView, ViewGroup list) 
	{
		View element;
		
		if (convertView == null) {
			LayoutInflater inflater = context_.getLayoutInflater();
			element = inflater.inflate(R.layout.city, null);
		} 
		else {
			element = convertView;
		}
		
		TextView cityTV = (TextView)element.findViewById(R.id.city_name);

		cityTV.setText(cities_.get(position).getName());

		return element;
	}

	/**
	 * Intoarce numarul de elemente din lista.
	 * 
	 * @return numarul de elemente
	 */
    public int getCount ()
    {
		return cities_.size ();
	}

    /**
     * Sterge tot continutul listei.
     */
    public void clear()
    {
    	cities_.clear();
		this.notifyDataSetChanged();
    }
    
    /**
     * Intoarce elementul de pe pozitia "position" din model (lista).
     * 
     * @return elementul respectiv
     */
	public Object getItem(int position) 
	{
		return cities_.get(position);
	}

	/**
	 * Intoarce id-ul elementului din lista.
	 * 
	 * @param position - pozitia elementului
	 * 
	 * @return id-ul 
	 */
	public long getItemId(int position) 
	{
		/**
		 * Nu este obligatoriu ca fiecare element sa aiba un id.
		 */
		return 0;
	}

	/**
	 * Adauga un nou element City (un oras) in lista.
	 * 
	 * @param name - numele orasului
	 */
	public void addCity(String name)
	{
		int comp;		
		
		City c = new City(name.toUpperCase());
		
		for (int i = 0; i < cities_.size(); i++) {
			comp = cities_.get(i).compareTo(c);
			
			// Egalitate, inseamna ca exista un obiect in lista.
			// Nu il adaug in lista.
			if (comp == 0) {
				return;
			}
			// Am gasit primul element mai mare in ordine lexicografica.
			// Il adaug in pozitia "i" al elementului, restul listei fiind
			// deplasat cu o pozitie in dreapta.
			if (comp > 0) {
				cities_.add (i, c);

				this.notifyDataSetChanged();
				return;
			}
		}
		
		// Il adaug la sfarsitul listei.
		cities_.add(c);
		
		// Acesta functie deterimina adaptorul sa ceara listei sa reafiseze continutul.
		this.notifyDataSetChanged();
	}
	
	/**
	 * Sterge un element (oras) din lista.
	 * 
	 * @param c - orasul ce va fi sters
	 */
	public void removeCity(City c)
	{
		cities_.remove(c);
		
		// Acesta functie deterimina adaptorul sa ceara listei sa reafiseze continutul.
		this.notifyDataSetChanged();
	}
}


/**
 * Clasa implementeaza acitivitatea principala, Main.
 * Din aceasta activitate se poate adauga un oras prin apasarea pe butonul
 * "Add City", afisarea informatiilor despre un oras prin selectarea lui din
 * lista (apasare scurta) sau stergerea lui prin apasare lunga.
 * 
 * @author Vlase Paul
 *
 */
public class MainActivity extends ListActivity 
		implements View.OnClickListener
{
	/**
	 * Butonul de adaugare a unui oras ("Add City"
	 */
	Button addButton_;
	
	/**
	 * Adaptorul pentru lista (model)
	 */
	CityListAdapter adapter;
	
	/** 
	 * Intetul pentru deschiderea activitatii de adaugare a unui oras 
	 * "AddCityActivity".
	 */
	Intent addIntent_;
	
	/** 
	 * Numele fisierului in care va fi stocata lista intern
	 */
	String cacheFile = "city_list.txt";

    /**
     *  Called when the activity is first created.
     */	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        
        // Lista cu orase
        adapter = new CityListAdapter (this);
        setContentView (R.layout.main_activity);
        setListAdapter (adapter);
        
        //Butonul de adaugare
        addButton_ = (Button) findViewById(R.id.addButon);
        addButton_.setOnClickListener(this);
        
        // Intetul de deschidere a dialogului de adaugare oras
        addIntent_ = new Intent ();
        addIntent_.setClass(this, AddCityActivity.class); 

        
        // Listener pentru apasare lunga.
        // Se sterge elementul selectat din lista
        getListView().setOnItemLongClickListener(new OnItemLongClickListener() 
		{
			public boolean onItemLongClick(AdapterView<?> listAdapter, View view,
					int position, long id) 
			{
		        City c = (City) adapter.getItem (position);
		        
		        adapter.removeCity(c);
				return true;
			}
		});  
        
        
    	try {
    		// Deschiderea si citirea fisierului in care sunt stocate 
    		//orasele din lista
	    	InputStream in = openFileInput(cacheFile);
	    	if (in != null) {
		    	InputStreamReader tmp = new InputStreamReader(in);
		    	BufferedReader reader = new BufferedReader(tmp);
		    	String str;
 
 
		    	while ((str = reader.readLine()) != null) {
		    		// Adaugarea fiecarui oras de pe linie in lista
		    		adapter.addCity(str);
		    	}
		    	in.close();
 
	    	}
    	} catch (java.io.FileNotFoundException e) {
    		// That's OK, we probably haven't created it yet
    	} catch (Throwable t) {
    	}
    }
    
    /**
     * Actiuni executate la inreruperea activitatii
     */
    public void onPause() {
    	super.onPause();
    	try {
    		//Deschiderea fisierului de stocare a oraselor
	    	OutputStreamWriter out = new OutputStreamWriter(
	    			openFileOutput(cacheFile, 0));
	    	
	    	City c;
	    	
	    	// Stocarea numelor oraselor in fisier, cate unul pe o linie
	    	for (int i = 0; i < adapter.getCount(); i++) {
	    		c = (City) adapter.getItem(i);
	    		out.write(c.getName() + "\n");
	    	}

	    	
	    	out.close();
	    	
	    	
    	} catch (Throwable t) {
    	}
    }    
    
    /**
     * Actiunea pentru click pe butonul de adaugare addButton_
     */
	public void onClick(View v) {
		// Pornirea activitatii dialogului AddCityActivity
		startActivityForResult (addIntent_, 100);
	}
	
	/**
	 * Rezultatul primit din dialogul de adaugare a unui oras
	 */
    @Override
    public void onActivityResult (int requestCode, int responseCode, 
    		Intent responseIntent)
    {
    	// Dialogul de adaugare
    	if (requestCode == 100)
    	{
    		// S-a apasat butonul Add
    		if (responseCode==1)
    		{
    			String city = responseIntent.getStringExtra("city");
    	    	
    			// Adaug orasul in lista
    			adapter.addCity(city);
    		}
    		// S-a apasat butonul Cancel
    		else 
    			if (responseCode==0)
    			{   				
    			}
    	}
    }
    
    /**
     * Listener pentru actiunea de apasare scurta pe un element din lista.
     * Deschid activitatea "WeatherInfoActivity" pentru a afisa informatiile
     * meteo pentru orasul respectiv.
     */
    @Override
    public void onListItemClick (ListView list, View v, int position, long id)
    {
        City c = (City) adapter.getItem (position);
        
        Intent intent = new Intent ();
         
        intent.setClass(this, WeatherInfoActivity.class);
         
        // Setam un parametru pentru intent, un String cu 
        // numele "city", numele orasului
        intent.putExtra("city", c.getName());
         
        // Componenta de destinatie stim ca este o activitate, deci emitem 
        // Intent-ul cu startActivity. Atentie, functia startActivity intoarce
        // imediat, urmand ca sistemul sa porneasca la un moment dat fereastra.
        startActivity (intent);        
    }
}